飞桨深度学习零基础入门(二) 您所在的位置:网站首页 基于卷积神经网络的手写识别 怎么实现 飞桨深度学习零基础入门(二)

飞桨深度学习零基础入门(二)

2023-12-03 13:23| 来源: 网络整理| 查看: 265

系列文章往期回顾

飞桨深度学习零基础入门(序)——Python实现梯度下降 飞桨深度学习零基础入门(一)——使用飞桨(Paddle)单层神经网络预测波士顿房价

使用飞浆实现卷积神经网络的手写数字识别 系列文章往期回顾引入依赖包定义数据集读取器定义模型结构训练正则化模型评估可视化使用matplotlib进行可视化visualDL可视化 代码下载

引入依赖包 import os import random import paddle import paddle.nn.functional as F from paddle.nn import Conv2D, MaxPool2D, Linear import numpy as np from PIL import Image import gzip import json 定义数据集读取器 def load_data(mode='train'): # 读取数据文件 datafile = './work/mnist.json.gz' print('loading mnist dataset from {} ......'.format(datafile)) data = json.load(gzip.open(datafile)) # 读取数据集中的训练集,验证集和测试集 train_set, val_set, eval_set = data # 数据集相关参数,图片高度IMG_ROWS, 图片宽度IMG_COLS IMG_ROWS = 28 IMG_COLS = 28 # 根据输入mode参数决定使用训练集,验证集还是测试 if mode == 'train': imgs = train_set[0] labels = train_set[1] elif mode == 'valid': imgs = val_set[0] labels = val_set[1] elif mode == 'eval': imgs = eval_set[0] labels = eval_set[1] # 获得所有图像的数量 imgs_length = len(imgs) # 验证图像数量和标签数量是否一致 assert len(imgs) == len(labels), \ "length of train_imgs({}) should be the same as train_labels({})".format( len(imgs), len(labels)) index_list = list(range(imgs_length)) # 读入数据时用到的batchsize BATCHSIZE = 100 # 定义数据生成器 def data_generator(): # 训练模式下,打乱训练数据 if mode == 'train': random.shuffle(index_list) imgs_list = [] labels_list = [] # 按照索引读取数据 for i in index_list: # 读取图像和标签,转换其尺寸和类型 img = np.reshape(imgs[i], [1, IMG_ROWS, IMG_COLS]).astype('float32') label = np.reshape(labels[i], [1]).astype('int64') imgs_list.append(img) labels_list.append(label) # 如果当前数据缓存达到了batch size,就返回一个批次数据 if len(imgs_list) == BATCHSIZE: yield np.array(imgs_list), np.array(labels_list) # 清空数据缓存列表 imgs_list = [] labels_list = [] # 如果剩余数据的数目小于BATCHSIZE, # 则剩余数据一起构成一个大小为len(imgs_list)的mini-batch if len(imgs_list) > 0: yield np.array(imgs_list), np.array(labels_list) return data_generator 定义模型结构 class MNIST(paddle.nn.Layer): def __init__(self): super(MNIST, self).__init__() # 定义卷积层,输出特征通道out_channels设置为20,卷积核的大小kernel_size为5,卷积步长stride=1,padding=2 self.conv1 = Conv2D(in_channels=1, out_channels=20, kernel_size=5, stride=1, padding=2) # 定义池化层,池化核的大小kernel_size为2,池化步长为2 self.max_pool1 = MaxPool2D(kernel_size=2, stride=2) # 定义卷积层,输出特征通道out_channels设置为20,卷积核的大小kernel_size为5,卷积步长stride=1,padding=2 self.conv2 = Conv2D(in_channels=20, out_channels=20, kernel_size=5, stride=1, padding=2) # 定义池化层,池化核的大小kernel_size为2,池化步长为2 self.max_pool2 = MaxPool2D(kernel_size=2, stride=2) # 定义一层全连接层,输出维度是10 self.fc = Linear(in_features=980, out_features=10) #加入对每一层输入和输出的尺寸和数据内容的打印,根据check参数决策是否打印每层的参数和输出尺寸 # 卷积层激活函数使用Relu,全连接层激活函数使用softmax def forward(self, inputs, label=None, check_shape=False, check_content=False): # 给不同层的输出不同命名,方便调试 outputs1 = self.conv1(inputs) outputs2 = F.relu(outputs1) outputs3 = self.max_pool1(outputs2) outputs4 = self.conv2(outputs3) outputs5 = F.relu(outputs4) outputs6 = self.max_pool2(outputs5) outputs6 = paddle.reshape(outputs6, [outputs6.shape[0], -1]) outputs7 = self.fc(outputs6) # 选择是否打印神经网络每层的参数尺寸和输出尺寸,验证网络结构是否设置正确 if check_shape: # 打印每层网络设置的超参数-卷积核尺寸,卷积步长,卷积padding,池化核尺寸 print("\n########## print network layer's superparams ##############") print("conv1-- kernel_size:{}, padding:{}, stride:{}".format(self.conv1.weight.shape, self.conv1._padding, self.conv1._stride)) print("conv2-- kernel_size:{}, padding:{}, stride:{}".format(self.conv2.weight.shape, self.conv2._padding, self.conv2._stride)) #print("max_pool1-- kernel_size:{}, padding:{}, stride:{}".format(self.max_pool1.pool_size, self.max_pool1.pool_stride, self.max_pool1._stride)) #print("max_pool2-- kernel_size:{}, padding:{}, stride:{}".format(self.max_pool2.weight.shape, self.max_pool2._padding, self.max_pool2._stride)) print("fc-- weight_size:{}, bias_size_{}".format(self.fc.weight.shape, self.fc.bias.shape)) # 打印每层的输出尺寸 print("\n########## print shape of features of every layer ###############") print("inputs_shape: {}".format(inputs.shape)) print("outputs1_shape: {}".format(outputs1.shape)) print("outputs2_shape: {}".format(outputs2.shape)) print("outputs3_shape: {}".format(outputs3.shape)) print("outputs4_shape: {}".format(outputs4.shape)) print("outputs5_shape: {}".format(outputs5.shape)) print("outputs6_shape: {}".format(outputs6.shape)) print("outputs7_shape: {}".format(outputs7.shape)) # print("outputs8_shape: {}".format(outputs8.shape)) # 选择是否打印训练过程中的参数和输出内容,可用于训练过程中的调试 if check_content: # 打印卷积层的参数-卷积核权重,权重参数较多,此处只打印部分参数 print("\n########## print convolution layer's kernel ###############") print("conv1 params -- kernel weights:", self.conv1.weight[0][0]) print("conv2 params -- kernel weights:", self.conv2.weight[0][0]) # 创建随机数,随机打印某一个通道的输出值 idx1 = np.random.randint(0, outputs1.shape[1]) idx2 = np.random.randint(0, outputs4.shape[1]) # 打印卷积-池化后的结果,仅打印batch中第一个图像对应的特征 print("\nThe {}th channel of conv1 layer: ".format(idx1), outputs1[0][idx1]) print("The {}th channel of conv2 layer: ".format(idx2), outputs4[0][idx2]) print("The output of last layer:", outputs7[0], '\n') # 如果label不是None,则计算分类精度并返回 if label is not None: acc = paddle.metric.accuracy(input=F.softmax(outputs7), label=label) return outputs7, acc else: return outputs7 训练 #在使用GPU机器时,可以将use_gpu变量设置成True use_gpu = False paddle.set_device('gpu:0') if use_gpu else paddle.set_device('cpu') train_loader = load_data('train') def train(model): model = MNIST() model.train() #四种优化算法的设置方案,可以逐一尝试效果 opt = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters()) # opt = paddle.optimizer.Momentum(learning_rate=0.01, momentum=0.9, parameters=model.parameters()) # opt = paddle.optimizer.Adagrad(learning_rate=0.01, parameters=model.parameters()) # opt = paddle.optimizer.Adam(learning_rate=0.01, parameters=model.parameters()) EPOCH_NUM = 1 for epoch_id in range(EPOCH_NUM): for batch_id, data in enumerate(train_loader()): #准备数据,变得更加简洁 images, labels = data images = paddle.to_tensor(images) labels = paddle.to_tensor(labels) #前向计算的过程,同时拿到模型输出值和分类准确率 if batch_id == 0 and epoch_id==0: # 打印模型参数和每层输出的尺寸 predicts, acc = model(images, labels, check_shape=True, check_content=False) elif batch_id==401: # 打印模型参数和每层输出的值 predicts, acc = model(images, labels, check_shape=False, check_content=True) else: predicts, acc = model(images, labels) #计算损失,取一个批次样本损失的平均值 loss = F.cross_entropy(predicts, labels) avg_loss = paddle.mean(loss) #每训练了100批次的数据,打印下当前Loss的情况 if batch_id % 200 == 0: print("epoch: {}, batch: {}, loss is: {}, acc is {}".format(epoch_id, batch_id, avg_loss.numpy(), acc.numpy())) #后向传播,更新参数的过程 avg_loss.backward() opt.step() opt.clear_grad() #保存模型参数 paddle.save(model.state_dict(), 'mnist_test.pdparams') #创建模型 model = MNIST() #启动训练过程 train(model) print("Model has been saved.") 正则化 def train(model): model.train() #各种优化算法均可以加入正则化项,避免过拟合,参数regularization_coeff调节正则化项的权重 opt = paddle.optimizer.Adam(learning_rate=0.01, weight_decay=paddle.regularizer.L2Decay(coeff=1e-5), parameters=model.parameters()) EPOCH_NUM = 5 for epoch_id in range(EPOCH_NUM): for batch_id, data in enumerate(train_loader()): #准备数据,变得更加简洁 images, labels = data images = paddle.to_tensor(images) labels = paddle.to_tensor(labels) #前向计算的过程,同时拿到模型输出值和分类准确率 predicts, acc = model(images, labels) #计算损失,取一个批次样本损失的平均值 loss = F.cross_entropy(predicts, labels) avg_loss = paddle.mean(loss) #每训练了100批次的数据,打印下当前Loss的情况 if batch_id % 200 == 0: print("epoch: {}, batch: {}, loss is: {}, acc is {}".format(epoch_id, batch_id, avg_loss.numpy(), acc.numpy())) #后向传播,更新参数的过程 avg_loss.backward() opt.step() opt.clear_grad() #保存模型参数 paddle.save(model.state_dict(), 'mnist_regul.pdparams') model = MNIST() train(model) 模型评估 def evaluation(model): print('start evaluation .......') # 定义预测过程 params_file_path = 'mnist.pdparams' # 加载模型参数 param_dict = paddle.load(params_file_path) model.load_dict(param_dict) model.eval() eval_loader = load_data('eval') acc_set = [] avg_loss_set = [] for batch_id, data in enumerate(eval_loader()): images, labels = data images = paddle.to_tensor(images) labels = paddle.to_tensor(labels) predicts, acc = model(images, labels) loss = F.cross_entropy(input=predicts, label=labels) avg_loss = paddle.mean(loss) acc_set.append(float(acc.numpy())) avg_loss_set.append(float(avg_loss.numpy())) #计算多个batch的平均损失和准确率 acc_val_mean = np.array(acc_set).mean() avg_loss_val_mean = np.array(avg_loss_set).mean() print('loss={}, acc={}'.format(avg_loss_val_mean, acc_val_mean)) model = MNIST() evaluation(model) 可视化 使用matplotlib进行可视化 import matplotlib.pyplot as plt def train(model): model.train() opt = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters()) EPOCH_NUM = 5 iter=0 iters=[] losses=[] for epoch_id in range(EPOCH_NUM): for batch_id, data in enumerate(train_loader()): #准备数据,变得更加简洁 images, labels = data images = paddle.to_tensor(images) labels = paddle.to_tensor(labels) #前向计算的过程,同时拿到模型输出值和分类准确率 predicts, acc = model(images, labels) #计算损失,取一个批次样本损失的平均值 loss = F.cross_entropy(predicts, labels) avg_loss = paddle.mean(loss) #每训练了100批次的数据,打印下当前Loss的情况 if batch_id % 100 == 0: print("epoch: {}, batch: {}, loss is: {}, acc is {}".format(epoch_id, batch_id, avg_loss.numpy(), acc.numpy())) iters.append(iter) losses.append(avg_loss.numpy()) iter = iter + 100 #后向传播,更新参数的过程 avg_loss.backward() opt.step() opt.clear_grad() #保存模型参数 paddle.save(model.state_dict(), 'mnist.pdparams') return iters, losses model = MNIST() iters, losses = train(model) plt.figure() plt.title("train loss", fontsize=24) plt.xlabel("iter", fontsize=14) plt.ylabel("loss", fontsize=14) plt.plot(iters, losses,color='red',label='train loss') plt.grid() plt.show()

在这里插入图片描述

visualDL可视化 from visualdl import LogWriter log_writer = LogWriter(logdir="./log") def train(model): model.train() opt = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters()) EPOCH_NUM = 5 iter = 0 for epoch_id in range(EPOCH_NUM): for batch_id, data in enumerate(train_loader()): #准备数据,变得更加简洁 images, labels = data images = paddle.to_tensor(images) labels = paddle.to_tensor(labels) #前向计算的过程,同时拿到模型输出值和分类准确率 predicts, avg_acc = model(images, labels) #计算损失,取一个批次样本损失的平均值 loss = F.cross_entropy(predicts, labels) avg_loss = paddle.mean(loss) #每训练了100批次的数据,打印下当前Loss的情况 if batch_id % 100 == 0: print("epoch: {}, batch: {}, loss is: {}, acc is {}".format(epoch_id, batch_id, avg_loss.numpy(), avg_acc.numpy())) log_writer.add_scalar(tag = 'acc', step = iter, value = avg_acc.numpy()) log_writer.add_scalar(tag = 'loss', step = iter, value = avg_loss.numpy()) iter = iter + 100 #后向传播,更新参数的过程 avg_loss.backward() opt.step() opt.clear_grad() #保存模型参数 paddle.save(model.state_dict(), 'mnist.pdparams') model = MNIST() train(model)

在文件保存目录下使用命令行(cmd)输入后打开对应网页的目录,就可以像使用tensorboard一样使用visualDL了。

visualdl --logdir ./log --port 8080 代码下载

代码下载地址:飞桨实现卷积神经网络手写数字识别



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有